package org.tinygame.herostory;

import com.google.protobuf.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 自定义的消息解码器，ChannelInboundHandlerAdapter
 * 这是一个入站处理器
 */
public class GameMsgDecoder extends ChannelInboundHandlerAdapter {
    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(GameMsgDecoder.class);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //如果不是BinaryWebSocketFrame类的消息，直接返回，不做解码处理
        if (!(msg instanceof BinaryWebSocketFrame)){
            return;
        }
        //WebSocket 二进制消息会通过 HttpServerCodec 解码成 BinaryWebSocketFrame 类对象
        BinaryWebSocketFrame frame = (BinaryWebSocketFrame) msg;
        /**
         * 从frame.content()拿到的数据包，包含消息长度、消息编号、消息体三部分
         * 我们需要对这三部分进行拆分
         */
        ByteBuf byteBuf = frame.content();

        byteBuf.readShort();//读取消息的长度
        int msgCode = byteBuf.readShort();//读取消息的编号
        //根据协议中的msgCode，获取不同的消息构建器
        Message.Builder msgBuilder = GameMsgRecognizer.getBuilderByMsgCode(msgCode);

        if (null == msgBuilder ){
            LOGGER.error("无法识别的消息,msgCode {}",msgCode);
            return;
        }

        byte[] msgBody = new byte[byteBuf.readableBytes()];//读取消息的消息体数据
        byteBuf.readBytes(msgBody); //将消息体数据写入到byteBuf中，经过这一步，byteBuf中只有消息体数据，完成了拆包

        msgBuilder.clear();//清除消息构建器中的数据，以防万一
        msgBuilder.mergeFrom(msgBody);
        Message newMsg = msgBuilder.build();

        if (null != newMsg) {
            ctx.fireChannelRead(newMsg);
        }
    }
}
